﻿using Lossage.Net.Protocols.Connection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Lossage.Net.Protocols.Modbus
{

    class ModbusTCPHeader
    {
        UInt16 txNo;
        UInt16 rxNo;
        UInt16 protocolType; //ModbusTCP固定为0000
        UInt16 length;

        internal UInt16 TxNo { get => txNo; set => txNo = value; }
        internal UInt16 RxNo { get => rxNo; set => rxNo = value; }
        internal UInt16 ProtocolType { get => protocolType; set => protocolType = value; }
        internal UInt16 Length { get => length; set => length = value; }

        public IEnumerable<byte> ToArray()
        {
            var buffer = new byte[6];
            //buffer[0] = _this.TxNo
            //buffer[1] = _this.RxNo
            buffer[0] = (byte)(this.TxNo >> 8);
            buffer[1] = (byte)(this.TxNo & 0xFF);
            buffer[2] = (byte)(this.ProtocolType >> 8);
            buffer[3] = (byte)(this.ProtocolType & 0xFF);
            buffer[4] = (byte)(this.Length >> 8);
            buffer[5] = (byte)(this.Length & 0xFF);
            return buffer; //fmt.Sprintf("%2X-%2X-%4X-%4X", _this.TxNo, _this.RxNo, _this.ProtocolType, _this.Length)
        }
        public bool FromArray(IEnumerable<byte> buffer)
        {
            if (buffer == null || buffer.Count() != 6)
            {
                return false;
            }
            this.TxNo = (UInt16)((UInt16)(buffer.ElementAt(0) << 8) + (UInt16)(buffer.ElementAt(1)));
            this.RxNo = 0; //uint16(buffer[1])
            this.ProtocolType = (UInt16)((UInt16)(buffer.ElementAt(2) << 8) + (UInt16)(buffer.ElementAt(3)));
            this.Length = (UInt16)((UInt16)(buffer.ElementAt(4) << 8) + (UInt16)(buffer.ElementAt(5)));
            return true; //fmt.Sprintf("%2X-%2X-%4X-%4X", _this.TxNo, _this.RxNo, _this.ProtocolType, _this.Length)
        }
    }


    public class ModbusTCP : ModbusAction, IModbusTask
    {
        IConnectionClient conn;
        public event Action<IEnumerable<byte>> ReceiveEvent;
        public event Action<IEnumerable<byte>> SendEvent;
        ModbusTCPHeader senderHeader;
        ModbusTCPHeader receiveHeader;
        public ModbusTCP(string ip , int port, int timeOutMilsecond , bool autoReconnect ) 
        {
            conn = new TCPClient(ip, port, timeOutMilsecond, autoReconnect);
            senderHeader = new ModbusTCPHeader();
            receiveHeader = new ModbusTCPHeader();
        }
        
        public (ModbusModel receiver, ModbusModel sender) ReadOnce(byte adress, byte command, ushort startReg, byte regLen, ushort[] datas)
        {
            if (this.conn == null)
            {
                throw new Exception("tcp连接异常");
            }
            if (this.conn.IsConnecting)
            {
                throw new Exception("tcp连接中");
            }
            base.ReadOnce(adress, command, startReg, regLen);
            return (this.ReceiveFrame, this.SendFrame);
        }

        protected override IEnumerable<byte> read()
        {
            var buffer = this.conn.Read();
            if (this.ReceiveEvent != null)
            {
                this.ReceiveEvent(buffer);
            }
            this.receiveHeader.FromArray(buffer.Take(6));
            return buffer.Skip(6);
        }

        protected override bool write(IEnumerable<byte> data)
        {
            this.senderHeader.TxNo = (UInt16)(this.senderHeader.TxNo + 1);
            this.senderHeader.RxNo = this.receiveHeader.TxNo;
            this.senderHeader.Length = (UInt16)(data.Count());
            var headerBuffer = this.senderHeader.ToArray();
            data = headerBuffer.Concat(data);
            if (this.SendEvent != null)
            {
                this.SendEvent(data);
            }
            return this.conn.Write(data);
        }
    }
}
